#include "Avalon/Serialization/BinaryDeserializer.hpp"
#include "Avalon/IO/Buffer.hpp"

using namespace Avalon;
using namespace Avalon::IO;
using namespace Avalon::Serialization;
using namespace std;

BinaryDeserializer::BinaryDeserializer() {}

BinaryDeserializer::~BinaryDeserializer() {}

void BinaryDeserializer::SetDataSource(const void* source, int size) {
  m_source = source;
  m_remainingSize = size;
  m_readIterator = static_cast<const char*>(m_source);
}

void BinaryDeserializer::Shuttle(const char* name, bool& value) {
  DeserializePrimitive(value);
}

void BinaryDeserializer::Shuttle(const char* name, char& value) {
  DeserializePrimitive(value);
}

void BinaryDeserializer::Shuttle(const char* name, short& value) {
  DeserializePrimitive(value);
}

void BinaryDeserializer::Shuttle(const char* name, int& value) {
  DeserializePrimitive(value);
}

void BinaryDeserializer::Shuttle(const char* name, long& value) {
  DeserializePrimitive(value);
}

void BinaryDeserializer::Shuttle(const char* name, long long& value) {
  DeserializePrimitive(value);
}

void BinaryDeserializer::Shuttle(const char* name, float& value) {
  DeserializePrimitive(value);
}

void BinaryDeserializer::Shuttle(const char* name, double& value) {
  DeserializePrimitive(value);
}

void BinaryDeserializer::Shuttle(const char* name, std::string& value) {
  int size;
  DeserializePrimitive(size);
  if(size < 0 || size > m_remainingSize) {
    BOOST_THROW_EXCEPTION(SerializationException(
      "String length out of range."));
  }
  value = string(m_readIterator, size);
  m_readIterator += size;
  m_remainingSize -= size;
}

void BinaryDeserializer::Shuttle(const char* name, Buffer& data) {
  int size;
  DeserializePrimitive(size);
  if(size < 0 || size > m_remainingSize) {
    BOOST_THROW_EXCEPTION(SerializationException(
      "Buffer length out of range."));
  }
  data.Reserve(size);
  memcpy(data.GetMutableData(), m_readIterator, size);
  m_readIterator += size;
  m_remainingSize -= size;
}

template<typename T>
void BinaryDeserializer::DeserializePrimitive(T& value) {
  if(sizeof(T) > m_remainingSize) {
    BOOST_THROW_EXCEPTION(SerializationException("Data length out of range."));
  }
  value = *reinterpret_cast<const T*>(m_readIterator);
  m_readIterator += sizeof(T);
  m_remainingSize -= sizeof(T);
}
